package cn.xiaopengstack.infrastructure.persistent.repository;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import cn.xiaopengstack.domain.rebate.model.aggregate.BehaviorRebateAggregate;
import cn.xiaopengstack.domain.rebate.model.entity.BehaviorRebateOrderEntity;
import cn.xiaopengstack.domain.rebate.model.entity.DailyBehaviorRebateEntity;
import cn.xiaopengstack.domain.rebate.model.valobj.BehaviorTypeVO;
import cn.xiaopengstack.domain.rebate.repository.IBehaviorRebateRepository;
import cn.xiaopengstack.domain.strategy.model.entity.UserEntity;
import cn.xiaopengstack.infrastructure.event.EventPublisher;
import cn.xiaopengstack.infrastructure.persistent.dao.IDailyBehaviorRebateDao;
import cn.xiaopengstack.infrastructure.persistent.dao.ITaskDao;
import cn.xiaopengstack.infrastructure.persistent.dao.IUserBehaviorRebateOrderDao;
import cn.xiaopengstack.infrastructure.persistent.po.DailyBehaviorRebate;
import cn.xiaopengstack.infrastructure.persistent.po.Task;
import cn.xiaopengstack.infrastructure.persistent.po.UserBehaviorRebateOrder;
import cn.xiaopengstack.types.event.BaseEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author jiangyangang
 */
@Repository
@Slf4j
public class BehaviorRebateRepository implements IBehaviorRebateRepository {

    @Resource
    private IDailyBehaviorRebateDao dailyBehaviorRebateDao;

    @Resource
    private IUserBehaviorRebateOrderDao userBehaviorRebateOrderDao;

    @Resource
    private ITaskDao taskDao;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private EventPublisher eventPublisher;

    @Resource
    private IDBRouterStrategy routerStrategy;

    @Override
    public List<DailyBehaviorRebateEntity> queryDailyBehaviorRebateListByType(String behaviorType) {
        List<DailyBehaviorRebate> dailyBehaviorRebates = dailyBehaviorRebateDao.queryListByBehaviorType(behaviorType);
        return dailyBehaviorRebates.stream().map(rebate -> {
            DailyBehaviorRebateEntity rebateEntity = new DailyBehaviorRebateEntity();
            BeanUtils.copyProperties(rebate, rebateEntity);
            rebateEntity.setBehaviorType(BehaviorTypeVO.of(rebate.getBehaviorType()));
            return rebateEntity;
        }).collect(Collectors.toList());
    }

    @Override
    public void saveDailyRebateOrder(List<BehaviorRebateAggregate> aggregates) {

        for (BehaviorRebateAggregate aggregate : aggregates) {

            UserBehaviorRebateOrder userBehaviorRebateOrder = new UserBehaviorRebateOrder();
            userBehaviorRebateOrder.setBehaviorType(aggregate.getOrderEntity().getDailyBehaviorRebateEntity().getBehaviorType().getCode());
            userBehaviorRebateOrder.setRebateConfig(aggregate.getDailyBehaviorRebateEntity().getRebateConfig());
            userBehaviorRebateOrder.setRebateType(aggregate.getDailyBehaviorRebateEntity().getRebateType());
            userBehaviorRebateOrder.setRebateDesc(aggregate.getDailyBehaviorRebateEntity().getRebateDesc());
            userBehaviorRebateOrder.setOrderId(aggregate.getOrderEntity().getOrderId());
            userBehaviorRebateOrder.setBizId(aggregate.getOrderEntity().getBizId());
            userBehaviorRebateOrder.setCreateTime(new Date());
            userBehaviorRebateOrder.setUpdateTime(new Date());
            userBehaviorRebateOrder.setUserId(aggregate.getOrderEntity().getUserEntity().getUserId());
            // 保存本地事务任务
            Task task = new Task();
            task.setUserId(aggregate.getTaskEntity().getUser().getUserId());
            task.setMessageId(aggregate.getTaskEntity().getMessageId());
            task.setMessage(aggregate.getTaskEntity().getMessage());
            task.setState(aggregate.getTaskEntity().getState().getCode());
            task.setTopic(aggregate.getTaskEntity().getTopic());
            task.setCreateTime(new Date());
            task.setUpdateTime(new Date());

            try {
                routerStrategy.doRouter(userBehaviorRebateOrder.getUserId());
                // 事务插入
                transactionTemplate.execute(status -> {
                    userBehaviorRebateOrderDao.insertSelective(userBehaviorRebateOrder);
                    taskDao.insertSelective(task);
                    return 1;
                });
            } finally {
                routerStrategy.clear();
            }

            // 发送MQ
            try {
                eventPublisher.publish(aggregate.getEvent());
                taskDao.updateTaskSendMessageCompleted(task);
            } catch (Exception e) {
                log.error("返利订单MQ发送失败 userId={}, bizId={}, behaviorType={}", aggregate.getOrderEntity().getUserEntity().getUserId(), aggregate.getOrderEntity().getOrderId(), aggregate.getOrderEntity().getDailyBehaviorRebateEntity().getBehaviorType().getCode());
                taskDao.updateTaskSendMessageFail(task);
            }

        }
    }

    @Override
    public boolean sendDailyRebateMessage(BaseEvent<?> event) {
        try {
            eventPublisher.publish(event);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public List<BehaviorRebateOrderEntity> queryOrderByOutBusinessNo(String userId, String businessNo) {
        UserBehaviorRebateOrder userBehaviorRebateOrder = new UserBehaviorRebateOrder();
        userBehaviorRebateOrder.setUserId(userId);
        userBehaviorRebateOrder.setOutBusinessNo(businessNo);
        List<UserBehaviorRebateOrder> orders = userBehaviorRebateOrderDao.queryOrderByOutBusinessNo(userBehaviorRebateOrder);

        if (CollectionUtils.isEmpty(orders)) {
            return Collections.emptyList();
        }

        return orders.stream().map(order -> {
            BehaviorRebateOrderEntity orderEntity = new BehaviorRebateOrderEntity();
            orderEntity.setUserEntity(UserEntity.builder().userId(order.getUserId()).build());
            orderEntity.setOrderId(order.getOrderId());
            orderEntity.setOutBusinessNo(order.getOutBusinessNo());
            orderEntity.setBizId(orderEntity.getBizId());
            orderEntity.setDailyBehaviorRebateEntity(DailyBehaviorRebateEntity.builder()
                    .behaviorType(BehaviorTypeVO.of(order.getBehaviorType()))
                    .rebateType(order.getRebateType())
                    .rebateDesc(order.getRebateDesc())
                    .rebateConfig(order.getRebateConfig())
                    .build());
            return orderEntity;
        }).collect(Collectors.toList());

    }
}
